home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-12-09 | 14.9 KB | 422 lines | [TEXT/KAHL] |
- // ConvertMovie makes a copy of a movie, converting its text tracks to
- // new text tracks with bit map representations of the text. The displayFlags
- // parameter allows one to add new display flags (such as normally time consuming
- // antialias and drop shadow) for the bit map images. The imageTrack parameter
- // indicates whether to save an image of the entire text track or just the
- // text box (as specified by the defaultTextBox field of the text descriptor).
- // The spatial parameter is a pointer to a compression information data structure
- // that specifies how to compress the text bit maps.
-
- // Note that the resulting movie file (as specified by the dstSpec parameter) will
- // need to be flattened if it contained any non-text tracks in order to make it
- // self-contained.
-
-
- #include <QuickDraw.h>
- #include <Files.h>
- #include <StandardFile.h>
- #include <Movies.h>
- #include <ImageCompression.h>
- #include "ConvertTextMovie.h"
-
- // Special Call to Text Media Handler
- pascal ComponentResult GetMetrics(MediaHandler mh, Handle metrics)
- FIVEWORDINLINE(0x2F3C, 0x04, 0x108, 0x7000, 0xA82A);
-
-
- #define FailNil(a) if ((a)==nil) goto bail;
- #define FailOSErr(a) if (err = a) goto bail;
- #define FailMemErr(a) {a; if (err = MemError()) goto bail;}
- #define FailMoviesErr(a) {a; if (err = GetMoviesError()) goto bail;}
-
- pascal OSErr ConvertAndAddTextTrack(Track srcTrack, Track dstTrack, long newDisplayFlags, Boolean imageTrack, SCSpatialSettings *spatial);
-
- pascal void ConvertMovie(FSSpec *srcSpec, FSSpec *dstSpec, long newDisplayFlags, Boolean imageTrack, SCSpatialSettings *spatial)
- {
- OSErr err = 0;
- Movie dstMovie = 0;
- Movie srcMovie = 0;
- Handle trackDataRef = 0;
- Track srcTrack;
- Track dstTrack;
- Handle srcDataRef;
- OSType srcDataRefType;
- long srcDataRefAttributes;
- short resRefNum = 0;
- Fixed width,height;
- OSType mediaType;
- Media srcMedia;
- Media dstMedia;
- TimeValue selectionTime, selectionDuration;
- GWorldPtr gw, movieWorld = 0;
- GDHandle gd;
- short dstRef = 0;
- short srcRef;
- short srcResID;
- short dstResID = 0;
- Rect bounds;
- WindowPtr movieWindow = 0;
- short numTracks, trackNum;
- Point pt;
-
- GetGWorld(&gw, &gd);
-
- // Open the source movie file
- FailOSErr( OpenMovieFile(srcSpec, &srcRef, fsRdPerm));
- srcResID = 0;
- FailOSErr( NewMovieFromFile(&srcMovie, srcRef, &srcResID, 0, 0, 0));
- CloseMovieFile(srcRef);
- srcRef = 0;
-
- // Create a new movie file for the destination
- CreateMovieFile(dstSpec, 'TVOD', 0, createMovieFileDeleteCurFile, &dstRef, &dstMovie);
- AddMovieResource(dstMovie, dstRef, &dstResID, 0);
-
- GetMovieBox(srcMovie, &bounds);
- OffsetRect(&bounds, -bounds.left, -bounds.top);
- SetMovieBox(srcMovie, &bounds);
-
- // Image the movie into an offscreen buffer
- FailOSErr( NewGWorld(&movieWorld, spatial->depth, &bounds, 0L, 0L, useTempMem));
- SetMovieGWorld(srcMovie, movieWorld, 0);
-
- OffsetRect(&bounds, 100, 100);
- // Create a new window to which we can copy the movie image during the conversion
- movieWindow = NewCWindow(0, &bounds, (StringPtr) "\pConverting...", true, noGrowDocProc, (WindowPtr)-1, false, 0);
- AlignWindow(movieWindow, false, &bounds, nil);
- SetMovieActive(srcMovie, true);
-
- SetPort((GrafPtr)movieWindow);
-
- // Iterate through the tracks, copying non-text tracks and converting text tracks
- numTracks = GetMovieTrackCount(srcMovie);
- for (trackNum = 1; trackNum <= numTracks; trackNum++) {
- ClearMoviesStickyError();
- srcTrack = GetMovieIndTrack(srcMovie, trackNum);
- srcMedia = GetTrackMedia(srcTrack);
-
- srcDataRef = nil;
-
- GetTrackDimensions(srcTrack, &width, &height);
- dstTrack = NewMovieTrack(dstMovie, width, height, GetTrackVolume(srcTrack));
-
- GetMediaHandlerDescription(srcMedia, &mediaType, 0L, 0L);
-
- if (mediaType == 'text') {
- // TEXT TRACK; CONVERT IT TO BITMAP ("BURNT TEXT") REPRESENTATION
- if (err = ConvertAndAddTextTrack(srcTrack, dstTrack, newDisplayFlags, imageTrack, spatial)) {
- //DebugStr((StringPtr) "\pError returned by ConvertAndAddTextTrack");
- goto bail;
- }
- } else {
- // NON-TEXT TRACK; COPY A REFERENCE
- // Obtain the data ref of the source media since we are making a reference copy of the track.
- // The user will need to flatten the resulting file if they want a stand alone movie file.
- err = GetMediaDataRef(srcMedia, 1, &srcDataRef, &srcDataRefType, &srcDataRefAttributes);
- dstMedia = NewTrackMedia( dstTrack, mediaType,
- GetMediaTimeScale(srcMedia), srcDataRef, srcDataRefType);
-
- selectionTime = 0;
- selectionDuration = GetMovieDuration(srcMovie);
-
- InsertTrackSegment(srcTrack, dstTrack, selectionTime, selectionDuration, 0);
- CopyTrackSettings(srcTrack, dstTrack);
-
- DisposeHandle(srcDataRef);
- srcDataRef = 0;
- }
- if (err = GetMoviesStickyError()) goto bail;
- }
-
- UpdateMovieResource(dstMovie, dstRef, dstResID, 0);
- err = GetMoviesError();
-
- bail:
- // Clean up
- SetGWorld(gw, gd);
- if (movieWorld) DisposeGWorld(movieWorld);
- if (srcRef) CloseMovieFile(srcRef);
- if (dstRef) CloseMovieFile(dstRef);
- if (srcMovie) DisposeMovie(srcMovie);
- if (dstMovie) DisposeMovie(dstMovie);
- if (movieWindow) DisposeWindow(movieWindow);
- }
-
- #define min(x,y) ((x) < (y)) ? (x) : (y)
- #define dfDontHilite (1L << 30)
- #define dfDontBitmap (1L << 29)
-
- pascal OSErr ConvertAndAddTextTrack(Track srcTrack, Track dstTrack, long newDisplayFlags, Boolean imageTrack, SCSpatialSettings *spatial)
- {
- OSErr err;
- Movie srcMovie = GetTrackMovie(srcTrack);
- Media textMedia;
- MediaHandler textMediaHandler;
- Media newTextMedia;
- short sampleFlags;
- Fixed width, height;
- RgnHandle trackRgn;
- long size, dataSize, newDataSize;
- TimeValue sampleTime, sampleDuration, thisTrackTime, nextTrackTime, interestingDuration, mediaTime;
- ImageDescriptionHandle idh = (ImageDescriptionHandle) NewHandleClear(sizeof(ImageDescription));
- Handle dataOut = NewHandle(4);
- TextDescriptionHandle tdh = (TextDescriptionHandle) NewHandleClear(sizeof(TextDescription));
- Ptr imageData = 0;
- Ptr descPtr;
- Ptr dataPtr;
- long descIndex;
- Handle metrics = NewHandle(0);
- GWorldPtr movieGW;
- GDHandle movieGD;
- GWorldPtr saveGW;
- GDHandle saveGD;
- Rect trackRect;
- Rect textBox;
- long compressedDataSize;
- Rect movieBox;
- WindowPtr movieWindow = 0;
- MatrixRecord trackMatrix, movieMatrix;
- long textLen;
-
- GetPort((GrafPtr*)&movieWindow);
- GetMovieBox(srcMovie, &movieBox);
-
- // Create new text media
- textMedia = GetTrackMedia(srcTrack);
- textMediaHandler = GetMediaHandler(textMedia);
- FailMoviesErr( newTextMedia = NewTrackMedia(dstTrack, 'text', GetMediaTimeScale(textMedia), 0L, 0L));
-
- // Copy info from source track
- err = CopyTrackSettings(srcTrack, dstTrack);
- FailMoviesErr( SetTrackLayer(dstTrack, GetTrackLayer(srcTrack)));
-
- // Find the first text sample
- thisTrackTime = GetTrackOffset(srcTrack);
- GetTrackNextInterestingTime(srcTrack, nextTimeMediaSample+nextTimeEdgeOK, thisTrackTime, kFix1,
- &nextTrackTime, &interestingDuration);
- SetMovieTimeValue(srcMovie, thisTrackTime);
-
- // Get the track bounds and set up for compressing text image
- trackRgn = GetTrackSegmentDisplayBoundsRgn(srcTrack, 0, GetTrackDuration(srcTrack));
- if (!trackRgn || EmptyRgn(trackRgn)) {
- err = -1;
- goto bail;
- }
- trackRect = (*trackRgn)->rgnBBox;
- GetMovieGWorld(srcMovie, &movieGW, &movieGD);
- FailOSErr( GetMaxCompressionSize(movieGW->portPixMap, &trackRect, spatial->depth, spatial->spatialQuality,
- spatial->codecType, 0, &size));
- FailMemErr( imageData = NewPtr(size));
-
- // Get track matrix so that when we compress the image we are looking
- // in the right place in the offscreen buffer
- GetMovieMatrix(srcMovie, &movieMatrix);
- GetTrackMatrix(srcTrack, &trackMatrix);
- ConcatMatrix(&movieMatrix, &trackMatrix);
-
- FailOSErr( BeginMediaEdits(newTextMedia));
- while (thisTrackTime >= 0) {
- TimeValue dur;
- short addFlags = 0;
- // Get the current sample
- mediaTime = TrackTimeToMediaTime(thisTrackTime, srcTrack);
- FailOSErr( GetMediaSample(textMedia, dataOut, 0, &dataSize, mediaTime, &sampleTime, &sampleDuration,
- (SampleDescriptionHandle) tdh, &descIndex, 0, 0, &sampleFlags));
-
- // Add in the new display flags (and set special dontHilite & dontBitmap flags)
- (*tdh)->displayFlags |= (newDisplayFlags + dfDontHilite + dfDontBitmap);
- err = SetMediaSampleDescription(textMedia, descIndex, (SampleDescriptionHandle) tdh);
-
- SetMovieTimeValue(srcMovie, thisTrackTime);
-
- newDataSize = dataSize;
-
- // Get the track bounds for this time; if imageTrack is true we will compress the entire track image
- // otherwise we just image that portion of the track specified by the defaultTextBox field
- DisposeRgn(trackRgn);
- trackRgn = GetTrackDisplayBoundsRgn(srcTrack); // rgn could change over time
- trackRect = (*trackRgn)->rgnBBox;
- if (imageTrack) {
- textBox = trackRect;
- OffsetRect(&textBox, -trackRect.left, -trackRect.top);
- (*tdh)->defaultTextBox = textBox;
- } else {
- textBox = (*tdh)->defaultTextBox;
- // fix up textBox so it doesn't extend beyond the track
- if (textBox.right > trackRect.right-trackRect.left)
- textBox.right = trackRect.right-trackRect.left;
- if (textBox.bottom > trackRect.bottom-trackRect.top)
- textBox.bottom = trackRect.bottom-trackRect.top;
- (*tdh)->defaultTextBox = textBox;
- }
-
- // Non-sync samples are hilite samples; we don't need to convert them
- if (sampleFlags & mediaSampleNotSync) {
- addFlags = mediaSampleNotSync;
- goto skipConversion;
- }
-
- // Force update
- MoviesTask(srcMovie, 0);
- MoviesTask(srcMovie, 0);
-
- // Copy bits to window (so the user sees something happening)
- CopyBits((BitMap*)&movieGW->portPixMap, (BitMap*)&movieWindow->portBits, &movieBox, &movieBox, srcCopy, 0);
-
- // Get text metrics data structure for current time (used by text media handler for hiliting)
- // This will be added to the text sample below
- FailOSErr( GetMetrics(textMediaHandler, metrics));
-
- // Use track matrix to find text box's location within the movie box
- TransformRect(&trackMatrix, &textBox, 0);
- // Safety code: Force text box to be within the bounds of the track
- textBox.right = min(textBox.right, trackRect.right);
- textBox.bottom = min(textBox.bottom, trackRect.bottom);
- // More safety code: Don't allow text box height to be too small
- if ((textBox.bottom - textBox.top) <= 4)
- textBox.bottom = trackRect.bottom;
-
- // Compress the text image
- GetGWorld(&saveGW, &saveGD);
- SetGWorld(movieGW, movieGD);
- ForeColor(blackColor);
- BackColor(whiteColor);
- FailOSErr( FCompressImage(movieGW->portPixMap, &textBox, spatial->depth, spatial->spatialQuality, spatial->codecType, 0, 0, 0, 0, 0, 0, idh, imageData));
- SetGWorld(saveGW, saveGD);
-
- /********************************************************************/
- /* Build the new text descriptor */
- /********************************************************************/
-
- // If defaultFontName isn't there then add one
- if ((long)&(*tdh)->defaultFontName - (long)(*tdh) >= (*tdh)->size) {
- short fontNumber = (*tdh)->defaultStyle.scrpFont;
- Str255 fontName;
- fontName[0] = 0;
-
- // fontNum of 0 or 1 is special case (sys or app font) -> Don't use name
- if (fontNumber != 0 && fontNumber != 1)
- GetFontName(fontNumber, fontName);
-
- FailMemErr( SetHandleSize((Handle)tdh, sizeof(TextDescription) + fontName[0]));
- BlockMove(fontName, (*tdh)->defaultFontName, fontName[0]+1);
-
- // Don't use sizeof(TextDescription) to set size, since it pads the length to an even byte
- (*tdh)->size = ((long)&(*tdh)->defaultFontName - (long)(*tdh) + 1) + fontName[0];
- }
-
- // increase text description handle size to account for size of the image descriptor + atom header bytes (8)
- FailMemErr( SetHandleSize((Handle)tdh, (*tdh)->size + (*idh)->idSize + 8));
- (*tdh)->size = (*tdh)->size + (*idh)->idSize + 8;
-
- HLock((Handle)tdh);
-
- // Point past the default font name
- descPtr = (Ptr)((long)&(*tdh)->defaultFontName + (*tdh)->defaultFontName[0] + 1);
-
- // image descriptor atom header
- *(long*)descPtr = (*idh)->idSize + 8;
- descPtr += 4;
- *(long*)descPtr = 'idsc';
- descPtr += 4;
-
- // copy image descriptor
- compressedDataSize = (*idh)->dataSize;
- (*idh)->dataSize = 0; // set to zero so that all image descs will be same (field is not used at decompress)
- BlockMove(*idh, descPtr, (*idh)->idSize);
-
- HUnlock((Handle)tdh);
-
- /********************************************************************/
- /* Build the new text sample */
- /********************************************************************/
-
- // Look for and delete any existing bitmap or metric data from existing sample
- textLen = *((short*) *dataOut);
- if (dataSize > (textLen + 2)) {
- // We got extra stuff
- Ptr dataPtr = (*dataOut) + textLen + 2;
- long dataLen;
-
- do {
- dataLen = *((long*) dataPtr);
- if (dataLen <= 0 || dataLen > dataSize) break; // safety check
-
- if (((*((long*) (dataPtr+4))) == 'imag') || ((*((long*) (dataPtr+4))) == 'metr')) {
- // Delete the atom by sliding the remaining data over to fill in the gap
- long restOfDataSize = dataSize - (dataPtr+dataLen - *dataOut);
- if (restOfDataSize > 0)
- BlockMove(dataPtr+dataLen, dataPtr, restOfDataSize);
- dataSize -= dataLen;
- } else
- dataPtr += dataLen;
- } while ((dataPtr - *dataOut) < dataSize);
- }
-
- // Add Compressed Image to SampleData
- newDataSize = dataSize + compressedDataSize + 16 + GetHandleSize(metrics); // 16 = size of 2 atom headers
-
- FailMemErr( SetHandleSize(dataOut, newDataSize));
-
- HLock(dataOut);
- dataPtr = *dataOut+dataSize;
-
- // 'imag' atom header
- *(long*)dataPtr = compressedDataSize + 16;
- dataPtr += 4;
- *(long*)dataPtr = 'imag';
- dataPtr += 4;
-
- // image data atom header
- *(long*)dataPtr = compressedDataSize + 8;
- dataPtr += 4;
- *(long*)dataPtr = 'idat';
- dataPtr += 4;
-
- // copy image data
- BlockMove(imageData, dataPtr, compressedDataSize);
-
- // copy text metrics
- BlockMove(*metrics, dataPtr+compressedDataSize, GetHandleSize(metrics));
-
- HUnlock(dataOut);
-
- skipConversion:
- // Turn off the don't hilite flag
- (*tdh)->displayFlags &= ~dfDontHilite;
- (*tdh)->displayFlags &= ~dfDontBitmap;
-
- // Add the new sample data to new media
- FailOSErr( AddMediaSample(newTextMedia, dataOut, 0, newDataSize, sampleDuration,
- (SampleDescriptionHandle) tdh, 1, addFlags, &sampleTime));
-
- // Insert media into same location (thisTrackTime) in new track
- if (interestingDuration < 0 || interestingDuration > sampleDuration) interestingDuration = sampleDuration;
- dur = GetTrackDuration(dstTrack);
- FailOSErr( InsertMediaIntoTrack(dstTrack, thisTrackTime, sampleTime, interestingDuration, kFix1));
- dur = GetTrackDuration(dstTrack);
-
- // Get time for next text sample
- GetTrackNextInterestingTime(srcTrack, nextTimeMediaSample, thisTrackTime, kFix1, &nextTrackTime, &interestingDuration);
- if (thisTrackTime == nextTrackTime) {
- //DebugStr((StringPtr)"\pGetTrackNextInterestingTime returned same time");
- goto bail;
- }
- thisTrackTime = nextTrackTime;
- }
- err = EndMediaEdits(newTextMedia);
-
-
- bail:
- DisposeHandle(dataOut);
- DisposeHandle((Handle)idh);
- DisposeHandle((Handle)tdh);
- DisposeHandle(metrics);
- if (imageData) DisposePtr(imageData);
- if (trackRgn) DisposeRgn(trackRgn);
-
- return err;
-
- }
-
-